
#include "stdio.h"
#include "iostream"
#include <sstream> // std::stringstream, std::stringbuf

#include <eXosip2/eXosip.h>
// # include <stdlib.h>
// # include <stdarg.h>
#include <string.h>
#include <netinet/in.h> // IPPROTO_UDP IPPROTO_TCP

using namespace std;

//该系数是由UAS维护的，UAS在接收到UAC的未鉴权报文后，给UAC回复401，在该报文中必须要带相关认证系数和认证方法
//UAS赋值的认证随机数
#define NONCE "9bd055"
//UAS默认加密算法
#define ALGORITHTHM "MD5"

//SIP From头部
class CSipFromHeader
{
public:
    CSipFromHeader()
    {
    }
    ~CSipFromHeader()
    {
    }
    void SetHeader(string addrCod, string addrI, string addrPor)
    {
        addrCode = addrCod;
        addrIp = addrI;
        addrPort = addrPor;
    }
    string GetFormatHeader()
    {
        std::stringstream stream;
        stream << "<sip: " << addrCode << "@" << addrIp << ":" << addrPort
               << ">";
        return stream.str();
    }
    //主机名称
    string GetRealName()
    {
        std::stringstream stream;
        stream << addrIp;
        return stream.str();
    }

private:
    string addrCode;
    string addrIp;
    string addrPort;
};

//SIP Contract头部
class CContractHeader : public CSipFromHeader
{
public:
    CContractHeader()
    {
    }
    ~CContractHeader()
    {
    }
    void SetContractHeader(string addrCod, string addrI, string addrPor,
                           int expire)
    {
        SetHeader(addrCod, addrI, addrPor);
        expires = expire;
    }
    string GetContractFormatHeader(bool bExpires)
    {
        if (!bExpires)
        {
            return GetFormatHeader();
        }
        else
        {
            string sTmp = GetFormatHeader();
            std::stringstream stream;
            stream << ";"
                   << "expires=" << expires;
            sTmp += stream.str();
            return sTmp;
        }
    }

private:
    int expires;
};

struct SipContextInfo
{
    //Sip层返回的请求的标志 响应时返回即可
    int sipRequestId;
    //维护一次注册
    string callId;
    //消息所属的功能方法名字符串
    string method;
    //地址编码@域名或IP地址:连接端口，例如sip:1111@127.0.0.1:5060
    CSipFromHeader from;
    //地址编码@域名或IP地址:连接端口，例如sip:1111@127.0.0.1:5060
    CSipFromHeader proxy;
    //地址编码@域名或IP地址:连接端口，例如sip:1111@127.0.0.1:5060
    CContractHeader contact;
    //消息内容,一般为DDCP消息体XML文档,或者具体协议帧要求的其他字符串文本
    string content;
    //响应状态信息
    string status;
    //超时,时间单位为秒
    int expires;
};

struct SipAuthInfo
{
    //平台主机名
    string digestRealm;
    //平台提供的随机数
    string nonce;
    //用户名
    string userName;
    //密码
    string response;
    //“sip:平台地址”,不需要uac赋值
    string uri;
    //加密算法MD5
    string algorithm;
};

struct sipRegisterInfo
{
    SipContextInfo baseInfo;
    SipAuthInfo authInfo;
    bool isAuthNull;
};

void parserRegisterInfo(osip_message_t *request, int iReqId,
                        sipRegisterInfo &regInfo)
{
    std::stringstream stream;
    regInfo.baseInfo.method = request->sip_method;
    regInfo.baseInfo.from.SetHeader(request->from->url->username,
                                    request->from->url->host, request->from->url->port);
    regInfo.baseInfo.proxy.SetHeader(request->to->url->username,
                                     request->to->url->host, request->to->url->port);
    //获取expires
    osip_header_t *header = NULL;
    {
        osip_message_header_get_byname(request, "expires",
                                       0, &header);
        if (NULL != header && NULL != header->hvalue)
        {
            regInfo.baseInfo.expires = atoi(header->hvalue);
        }
    }
    //contact字段
    osip_contact_t *contact = NULL;
    osip_message_get_contact(request, 0, &contact);
    if (NULL != contact)
    {
        regInfo.baseInfo.contact.SetContractHeader(contact->url->username,
                                                   contact->url->host, contact->url->port,
                                                   regInfo.baseInfo.expires);
    }
    //注册返回 由发送方维护的请求ID 接收方接收后原样返回即可
    regInfo.baseInfo.sipRequestId = iReqId;
    //CALL_ID
    {
        stream.str("");
        stream << request->call_id->number;
        regInfo.baseInfo.callId = stream.str();
    }
    //解析content消息
    osip_body_t *body = NULL;
    osip_message_get_body(request, 0, &body);
    if (body != NULL)
    {
        stream.str("");
        stream << body->body;
        regInfo.baseInfo.content = stream.str();
    }
    //鉴权信息
    osip_authorization_t *authentication = NULL;
    {
        osip_message_get_authorization(request, 0, &authentication);
        if (NULL == authentication)
        {
            regInfo.isAuthNull = true;
        }
        else
        {
            regInfo.isAuthNull = false;
            stream.str("");
            stream << authentication->username;
            regInfo.authInfo.userName = stream.str();
            stream.str("");
            stream << authentication->algorithm;
            regInfo.authInfo.algorithm = stream.str();
            stream.str("");
            stream << authentication->realm;
            regInfo.authInfo.digestRealm = stream.str();
            stream.str("");
            stream << authentication->nonce;
            regInfo.authInfo.nonce = stream.str();
            stream.str("");
            stream << authentication->response;
            regInfo.authInfo.response = stream.str();
            stream.str("");
            stream << authentication->uri;
            regInfo.authInfo.uri = stream.str();
        }
    }
    authentication = NULL;
}
void sendRegisterAnswer(eXosip_t *ctx, sipRegisterInfo &info)
{
    osip_message_t *answer = NULL;
    int iStatus;
    if (info.isAuthNull)
    {
        iStatus = 401;
    }
    else
    {
        iStatus = 200;
    }
    eXosip_lock(ctx);
    {
        int result = ::eXosip_message_build_answer(ctx, info.baseInfo.sipRequestId,
                                                   iStatus, &answer);
        if (iStatus == 401)
        {
            //由SIP库生成认证方法和认证参数发送客户端
            std::stringstream stream;
            string nonce = NONCE;
            string algorithm = ALGORITHTHM;
            stream << "Digest realm=\"" << info.baseInfo.from.GetRealName()
                   << "\",nonce=\"" << nonce
                   << "\",algorithm=" << algorithm;

            osip_message_set_header(answer, "WWW-Authenticate",
                                    stream.str().c_str());
            cout << "======================================================="
                    "========="
                 << endl;
            cout << "发送401报文" << endl;
            cout << "========================================================"
                    "========"
                 << endl;
        }
        else if (iStatus == 200)
        {
            osip_message_set_header(answer, "Contact",
                                    info.baseInfo.contact.GetContractFormatHeader(true).c_str());
            cout << "========================================================="
                    "======="
                 << endl;
            cout << "发送200报文" << endl;
            cout << "=========================================================="
                    "======"
                 << endl;
            //string_t b = "<sip: 100110000101000000@192.168.31.18:5061>;expires=600";
            //osip_message_set_header(answer, "Contact", b.c_str());
        }
        else
        {
            //Do nothing
        }

        if (OSIP_SUCCESS != result)
        {
            ::eXosip_message_send_answer(ctx, info.baseInfo.sipRequestId, 400, NULL);
        }
        else
        {
            //发送消息体
            ::eXosip_message_send_answer(ctx, info.baseInfo.sipRequestId, iStatus,
                                         answer);
        }
        if (0 == info.baseInfo.expires)
        {
            eXosip_register_remove(ctx, info.baseInfo.sipRequestId);
        }
    }
    eXosip_unlock(ctx);
}

//打印接收到的响应报文
void printRegisterPkt(sipRegisterInfo &info)
{
    cout << "接收到报文：" << endl;
    cout << "=============================================="
            "=================="
         << endl;
    cout << "method:" << info.baseInfo.method << endl;
    cout << "from:    " << info.baseInfo.from.GetFormatHeader() << endl;
    cout << "to:" << info.baseInfo.proxy.GetFormatHeader() << endl;
    cout << "contact:" << info.baseInfo.contact.GetContractFormatHeader(false)
         << endl;

    //注册返回 由发送方维护的请求ID 接收方接收后原样返回即可
    cout << "sipRequestId:" << info.baseInfo.sipRequestId << endl;
    //CALL_ID
    cout << "CallId:" << info.baseInfo.callId << endl;
    //解析content消息
    cout << "body:" << info.baseInfo.content << endl;
    //获取expires
    cout << "expires:" << info.baseInfo.expires << endl;
    //鉴权信息
    if (info.isAuthNull)
    {
        cout << "当前报文未提供鉴权信息!!!" << endl;
    }
    else
    {
        cout << "当前报文鉴权信息如下:" << endl;
        cout << "username:" << info.authInfo.userName << endl;
        cout << "algorithm:" << info.authInfo.algorithm << endl;
        cout << "Realm:" << info.authInfo.digestRealm << endl;
        cout << "nonce:" << info.authInfo.nonce << endl;
        cout << "response:" << info.authInfo.response << endl;
        cout << "uri:" << info.authInfo.uri << endl;
    }
    cout << "=================================================="
            "=============="
         << endl;
    return;
}

void OnRegister(eXosip_t *ctx, eXosip_event_t *osiosipEventPtr)
{
    sipRegisterInfo regInfo;
    parserRegisterInfo(osiosipEventPtr->request, osiosipEventPtr->tid, regInfo);
    //打印报文
    printRegisterPkt(regInfo);
    //发送应答报文
    sendRegisterAnswer(ctx, regInfo);
}

void printExosiosipEventPtr(eXosip_event_t *osipEventPtr)
{
    printf("---------------------------------------\n");
    printf("new sip event:%d\n", osipEventPtr->type);
    printf("textinfo:%s\n", osipEventPtr->textinfo);
    printf("tid:%d\n", osipEventPtr->tid);
    printf("---------------------------------------\n");

    /*
    REGISTER sip:41010200002000000001@10.0.0.42:15063 SIP/2.0
    Via: SIP/2.0/UDP 10.0.0.47:5060;rport;branch=z9hG4bK788252681
    Route: <sip:41010200001320000001@10.0.0.42:15063;lr>
    From: <sip:41010200001320000001@10.0.0.47:5060>;tag=823108582
    To: <sip:41010200001320000001@10.0.0.47:5060>
    Call-ID: 2084962507@10.0.0.47
    CSeq: 1 REGISTER
    Contact: <sip:41010200001320000001@10.0.0.47:5060>
    Max-Forwards: 70
    User-Agent: SIP UAS V2.1.4.488713
    Expires: 3600
    Content-Length: 0
    */

    // REGISTER sip:41010200002000000001@10.0.0.42:15063 SIP/2.0
    printf("method:%s\n", osipEventPtr->request->sip_method);
    printf("scheme:%s\n", osipEventPtr->request->req_uri->scheme);
    printf("username:%s\n", osipEventPtr->request->req_uri->username);
    printf("password:%s\n", osipEventPtr->request->req_uri->password);
    printf("host:%s\n", osipEventPtr->request->req_uri->host);
    printf("port:%s\n", osipEventPtr->request->req_uri->port);
    printf("version:%s\n", osipEventPtr->request->sip_version);

    // CSeq: 1 REGISTER
    printf("cseq.number:%s\n", osipEventPtr->request->cseq->number);
    printf("cseq.method:%s\n", osipEventPtr->request->cseq->method);

    printf("---------------------------------------\n");
}

int main(void)
{

    osip_message_t *ack = NULL;
    osip_message_t *invite = NULL;
    sdp_message_t *remote_sdp = NULL;
    int call_id, dialog_id;
    int i, j;
    int id;
    char *sour_call = "sip:140@127.0.0.1";
    char *dest_call = "sip:133@127.0.0.1:15060"; //client ip
    char command;
    char tmp[4096];
    char localip[128];
    int pos = 0;

    int port = 15063;
    int result;

    /*
    1)eXosip_init                            (初始化)
        |     
        v     
    2)eXosip_listen_addr                     (监听sip端口)
        |     
        v     
    3)eXosip_register_build_initial_register (构建一个register)
        |     
        v     
    4)eXosip_register_send_register          (发送register)
        |     
        v     
    5)eXosip_event_wait                      (等待对端事件)
        |     
        v     
    6)eXosip_execute                         (处理事件,调整内部状态)      //省略此步
        |     
        v     
    7)eXosip_automatic_action                (根据当前状况，发出响应消息)
    之后应循环执行 5）-》 7）
    */

    // 第一步 初始化
    eXosip_t *ctx = eXosip_malloc();
    result = eXosip_init(ctx);
    if (result != OSIP_SUCCESS)
    {
        printf("Can't initialize eXosip!\n");
        return -1;
    }
    else
    {
        printf("eXosip_init successfully!\n");
    }

    eXosip_add_authentication_info(ctx, "41010200002000000001", "12345678", "12345678", NULL, "yjkhtddx");

    /*
    UDP:
    i = eXosip_listen_addr (ctx, IPPROTO_UDP, NULL, 5060, AF_INET, 0);
    TCP:
    i = eXosip_listen_addr (ctx, IPPROTO_TCP, NULL, 5060, AF_INET, 0);
    TLS:
    i = eXosip_listen_addr (ctx, IPPROTO_TCP, NULL, 5061, AF_INET, 1);
    DTLS:
    i = eXosip_listen_addr (ctx, IPPROTO_UDP, NULL, 5061, AF_INET, 1);
    */

    result = eXosip_listen_addr(ctx, IPPROTO_UDP, NULL, port, AF_INET, 0);
    if (result != 0)
    {
        eXosip_quit(ctx);
        fprintf(stderr, "eXosip_listen_addr error!\nCouldn't initialize transport layer!\n");
    }
    else
    {
        printf("exosip listen port %d\n", port);
    }

    eXosip_event_t *osipEventPtr = nullptr;
    for (;;)
    {
        printf("wait...\n");
        //侦听是否有消息到来
        osipEventPtr = eXosip_event_wait(ctx, 0, 500);
        if (nullptr == osipEventPtr)
        {
            continue;
        }
        printExosiosipEventPtr(osipEventPtr);
        switch (osipEventPtr->type)
        {
        case EXOSIP_MESSAGE_NEW:
        {
            if (!strncmp(osipEventPtr->request->sip_method, "REGISTER",
                         strlen("REGISTER")))
            {
                printf("recive REGISTER\n");
                OnRegister(ctx, osipEventPtr);
                // osip_message_t *answer = NULL;
                // eXosip_message_build_answer(ctx, osipEventPtr->tid, 401, &answer);
                // eXosip_message_send_answer(ctx, osipEventPtr->tid, 401, answer);
                // eXosip_register_build_register();
                // OnRegister(osiosipEventPtrPtr)
            }
            else if (!strncmp(osipEventPtr->request->sip_method, "MESSAGE",
                              strlen("MESSAGE")))
            {
                printf("recive MESSAGE\n");
                // OnMessage(osiosipEventPtrPtr);
            }
        }
        break;

        default:
            break;
        }
    }

    // 结束
    eXosip_quit(ctx);
    ctx = nullptr;

    printf("Hello World\n");
    return 0;
}